#pragma once

#include "jsoncpp/json/json.h"
#include "compiler.hpp"
#include "runner.hpp"
#include "../Comm/comm.hpp"
#include "../Comm/util.hpp"
#include "../Comm/log.hpp"

namespace ns_complier_runner
{
    using namespace ns_util;
    using namespace ns_log;
    using namespace ns_compiler;
    using namespace ns_runner;

    class complier_runner
    {
    public:
        complier_runner() {}
        ~complier_runner() {}

    public:
        // unlink()根据路径删除某个文件
        static void RemoveTempFile(const std::string &file_name)
        {
            std::string _src = PathUtil::SRC(file_name);
            if (FileUtil::IsFileExict(_src))
                unlink(_src.c_str());

            std::string _compiler_error = PathUtil::Compiler_error(file_name);
            if (FileUtil::IsFileExict(_compiler_error))
                unlink(_compiler_error.c_str());

            std::string _exe = PathUtil::EXE(file_name);
            if (FileUtil::IsFileExict(_exe))
                unlink(_exe.c_str());

            std::string _in = PathUtil::IN(file_name);
            if (FileUtil::IsFileExict(_in))
                unlink(_in.c_str());

            std::string _out = PathUtil::OUT(file_name);
            if (FileUtil::IsFileExict(_out))
                unlink(_out.c_str());

            std::string _error = PathUtil::ERROR(file_name);
            if (FileUtil::IsFileExict(_error))
                unlink(_error.c_str());
        }

        /* --------------------------------------------------------------------------------
         * code = 0 : 代码编译和运行都无误
         * code < 0 : 内部错误 (代码为空(-1),创建子进程失败, 打开文件失败(-2), 编译失败(-3))
         * code > 0 : 进程收到信号导致异常崩溃
         --------------------------------------------------------------------------------*/
        static std::string CodeTODesc(int num, const std::string &file_name)
        {
            std::string desc;
            switch (num)
            {
            case 0:
                desc = "代码编译运行成功";
                break;
            case -1:
                desc = "代码为空";
                break;
            case -2:
                desc = "未知错误";
                break;
            case -3:
                FileUtil::ReadFromFile(PathUtil::Compiler_error(file_name), &desc, true);
                break;
            case SIGABRT:
                desc = "内存超过限制";
                break;
            case SIGFPE:
                desc = "浮点数溢出";
                break;
            case SIGXCPU:
                desc = "CPU使用超时";
                break;
            default:
                desc = "未知: " + std::to_string(num);
                break;
            }
            return desc;
        }
        /* --------------------------------------------------------------------------------
         * 输入:
         * code : 用户提交的代码
         * input : 用户给自己提交的代码对应的输入
         * cpu_limit : 时间要求
         * mem_limit : 空间要求
         * in_json: {"code":"#inclide ...", "input":"", "cpu_limit":1, "mem_limit":10240}
         *
         * 输出:
         * 必填->
         * status : 状态码
         * reason : 请求结果
         * 选填->
         * stdout : 运行完之后的结果
         * stderr : 运行完之后的错误结果(这里的错误结果是stderr流中的内容)
         * out_json: {"status": status_num, "reason": "", "stdout": "", "stderr": ""}
         --------------------------------------------------------------------------------*/
        static void Start(const std::string &in_json, std::string *out_json)
        {
            // 反序列化
            Json::Value in_root;
            Json::Reader reader;
            reader.parse(in_json, in_root);

            std::string code = in_root["code"].asString();
            std::string input = in_root["input"].asString();
            int cpu_limit = in_root["cpu_limit"].asInt();
            int mem_limit = in_root["mem_limit"].asInt();

            int status_num = 0;
            int run_result = 0;
            std::string file_name;
            Json::Value out_root;

            if (code.empty())
            {
                // 提交的代码为空
                status_num = -1;
                goto END;
            }

            // 创建一个具有唯一性的文件名, 没有路径和后缀
            file_name = FileUtil::UniqFileName();

            // 将code字符串写入到文件中
            if (!FileUtil::WriteToFile(PathUtil::SRC(file_name), code))
            {
                // 未知错误
                status_num = -2;
                goto END;
            }

            if (!compiler::Compile(file_name))
            {
                // 编译时错误
                status_num = -3;
                goto END;
            }

            run_result = runner::Run(file_name, cpu_limit, mem_limit);
            if (run_result < 0)
            {
                // 内部错误
                status_num = -2;
            }
            else if (run_result > 0)
            {
                // 出现异常,收到信号
                status_num = run_result;
            }
            else
            {
                // 程序编译运行成功
                status_num = 0;
            }
        END:
            out_root["status"] = status_num;
            out_root["reason"] = CodeTODesc(status_num, file_name);
            if (status_num == 0)
            {
                std::string stdout_content;
                FileUtil::ReadFromFile(PathUtil::OUT(file_name), &stdout_content, true);
                out_root["stdout"] = stdout_content;

                std::string stderr_content;
                FileUtil::ReadFromFile(PathUtil::ERROR(file_name), &stderr_content, true);
                out_root["stderr"] = stderr_content;
            }
            Json::StyledWriter writer;
            *out_json = writer.write(out_root);

            // RemoveTempFile(file_name);
        }
    };
} // namespace ns_complie_run
